#include "stdafx.h"

#ifndef DLL_SSE_CPP
#define DLL_SSE_CPP

#include "SSE.h"



// Loop over all the 4-components elements until there are < 4 left
#define SSE_FLOAT4_LOOP(num_floats)	\
	for( int offset = 0; offset < (num_floats>>2)<<2; offset+=4 )

// Treat the single elements left after the previous 4-components ones
#define SSE_FINAL_LOOP(num_floats)	\
	for( int offset=num_floats-num_floats%4; offset<num_floats; ++offset )


BBAEXPvoid FloatArraySetZeros( float *float_ptr, const int num_floats )
{ memset( float_ptr, 0, num_floats * sizeof(float) ); }


BBAEXPvoid FloatArrayAdd( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_add_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] += float_ptr1[offset];
}
BBAEXPvoid FloatArraySub( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_sub_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] -= float_ptr1[offset];
}
BBAEXPvoid FloatArrayMul( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_mul_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] *= float_ptr1[offset];
}
BBAEXPvoid FloatArrayDiv( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_div_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] /= float_ptr1[offset];
}
BBAEXPvoid FloatArraySqrt( float *float_ptr, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr+offset, _mm_sqrt_ps(_mm_loadu_ps(float_ptr+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr[offset] = sqrt(float_ptr[offset]);
}
BBAEXPvoid FloatArrayMin( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_min_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = float_ptr0[offset]<float_ptr1[offset] ? float_ptr0[offset] : float_ptr1[offset];
}
BBAEXPvoid FloatArrayMax( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_max_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = float_ptr0[offset]>float_ptr1[offset] ? float_ptr0[offset] : float_ptr1[offset];
}

BBAEXPvoid FloatArrayEqual( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmpeq_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] == float_ptr1[offset]) ? 1.f : 0.f;
}
BBAEXPvoid FloatArrayNotEqual( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmpneq_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] != float_ptr1[offset]) ? 1.f : 0.f;
}
BBAEXPvoid FloatArrayLess( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmplt_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] < float_ptr1[offset]) ? 1.f : 0.f;
}
BBAEXPvoid FloatArrayLessEqual( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmple_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] <= float_ptr1[offset]) ? 1.f : 0.f;
}
BBAEXPvoid FloatArrayGreater( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmpgt_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] > float_ptr1[offset]) ? 1.f : 0.f;
}
BBAEXPvoid FloatArrayGreaterEqual( float *float_ptr0, float *float_ptr1, const int num_floats ){
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr0+offset, _mm_cmpge_ps(_mm_loadu_ps(float_ptr0+offset), _mm_loadu_ps(float_ptr1+offset)) );
	SSE_FINAL_LOOP(num_floats) float_ptr0[offset] = (float_ptr0[offset] >= float_ptr1[offset]) ? 1.f : 0.f;
}



BBAEXPvoid FloatArrayAddFloat( float *float_ptr, const float scalar, const int num_floats ){
	__m128 add = _mm_set_ps1(scalar);
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr+offset, _mm_add_ps(_mm_loadu_ps(float_ptr+offset), add) );
	SSE_FINAL_LOOP(num_floats) float_ptr[offset] += scalar;
}

BBAEXPvoid FloatArrayMulFloat( float *float_ptr, const float scalar, const int num_floats ){
	__m128 mul = _mm_set_ps1(scalar);
	SSE_FLOAT4_LOOP(num_floats) _mm_storeu_ps( float_ptr+offset, _mm_mul_ps(_mm_loadu_ps(float_ptr+offset), mul) );
	SSE_FINAL_LOOP(num_floats) float_ptr[offset] *= scalar;
}

#undef SSE_FLOAT4_LOOP
#undef SSE_FINAL_LOOP

#endif //DLL_SSE_CPP